package com.zdxlz.desensitize.util;

import com.zdxlz.desensitize.constant.DesensitizeType;
import com.zdxlz.desensitize.constant.RegularConstant;

import java.util.Arrays;
import java.util.regex.Pattern;

/**
 * 脱敏工具类
 */
public class DesensitizeUtil {
    public DesensitizeUtil(){
        // Add a nested comment explaining why this method is empty
    }

    /**
     * 字符串脱敏
     */
    public String desensitized(String original, DesensitizeType type, Integer value) {
        if (null == original) {
            return null;
        }
        int length = original.length();
        if (length == 0) {
            return original;
        }
        if (null == type) {
            return original;
        }
        switch (type) {
            case EMPTY:
                return RegularConstant.EMPTY;
            case TO_FOUR_STARS:
                return RegularConstant.FOUR_STARS;
            case KEEP_FIRST:
                return keepFirst(original, length);
            case REMOVE_MIDDLE:
                return removeMiddle(original, length);
            case TO_STARS:
                return toStars(length);
            case EXTEND:
                return extend(original, length, value);
            case PHONE:
                return phone(original,length);
            case EMAIL:
                return email(original,length);
            case IDCARD:
                return idCard(original,length);
            case OFFICEPASS:
                return officePass(original,length, value);
            case ADDRESS:
                return address(original,length, value);
            case NAME:
                return name(original,length);
            case NOT:
            default:
                return original;
        }
    }

    /**
     * 继承并重写父类的extend方法扩展脱敏方法
     */
    public String extend(String original, int length, Integer value) {
        return original;
    }

    /**
     * 脱敏规则：只显示第一个字,比如李某某置换为李**, 李某置换为李*
     */
    public String keepFirst(String original, int length) {
        if (length == 0) {
            return original;
        }
        String target = original.substring(0,1);
        return rightPad(target, length, RegularConstant.STAR);
    }

    /**
     * 脱敏规则：只显示第一个字,比如李某某置换为李**, 李某置换为李*
     */
    public String name(String original, int length) {
        if (length == 0) {
            return original;
        }
        if (length >= 3) {
            return removeMiddle(original, length);
        }
        return keepFirst(original, length);
    }

    /**
     * 脱敏规则，全部变成*
     */
    public String toStars(int length) {
        return rightPad(RegularConstant.EMPTY, length, RegularConstant.STAR);
    }

    /**
     * 脱敏规则：保留前三分之一后三分之一, 比如10068158794置换为100****8794
     */
    public String removeMiddle(String original, int length) {
        if (length < 3) {
            return original;
        }
        long start = Math.round(length / 3.0);
        long end = start * 2-1;
        start--;
        StringBuilder sb = new StringBuilder(original);
        for (long i = start; i < end; i++) {
            sb.setCharAt((int) i, RegularConstant.STAR);
        }
        return sb.toString();
    }

    /**
     * 脱敏规则：去除后三分之一, 变成4个*，比如10068158794置换为1006815****
     */
    public String removeRight(String original, int length) {
        if (length < 3) {
            return original;
        }
        long end = Math.round(length / 3.0)* 2-1;
        return original.substring(0, (int) end)+RegularConstant.FOUR_STARS;
    }

    /**
     * 适用于手机号规则
     */
    public String phone(String original, int length){
        if (Pattern.matches(RegularConstant.CN_PHONE_PATTERN, original)){
            return removeMiddle(original, length);
        }
        return original;
    }

    /**
     * 地址
     */
    public String address(String address, int length, Integer value) {
        if (length < 3) {
            return address;
        }
        int i = 0;
        if (null != value) {
            i = value;
        }
        int sensitiveSize;
        if (0<i && i <= length){
            sensitiveSize = i;
        }else {
            sensitiveSize = (int) Math.round(length / 3.0);
        }
        return replace(address, length - sensitiveSize, length, RegularConstant.STAR);
    }
    
    /**
     * 军官证
     */
    public String officePass(String original, int length, Integer value) {
        if (length == 0) {
            return original;
        }
        int i = 0;
        if (null != value) {
            i = value;
        }
        int sensitiveSize;
        if (0<i && i <= length){
            sensitiveSize = i;
        }else {
            sensitiveSize = (int) Math.round(length / 3.0);
        }
        int start = length - sensitiveSize;
        String prefix = original.substring(0, start);
        String suffix = repeat(RegularConstant.STAR, sensitiveSize);
        return prefix + suffix;
    }

    /**
     * 身份证号遮掩4-12位
     */
    public String idCard(String original, int length) {
        if (length == 0) {
            return original;
        }
        if(Pattern.matches(RegularConstant.CN_IDCARD_PATTERN, original)){
            return original.replaceAll("(\\d{3})\\d{9}(\\w{1})","$1*********$2");
        }
        return original;
    }

    /**
     * 遮掩@前部分
     */
    public String email(String email, int length) {
        if (0==length) {
            return email;
        } else {
            int index = email.indexOf('@');
            return index <= 1 ? email : replace(email, 0, index, RegularConstant.STAR);
        }
    }

    /**
     * 密码
     */
    public String password(int length) {
        return toStars(length);
    }

    /**
     * 驾驶证
     */
    public String carLicense(String carLicense, int length) {
        if (0 != length) {
            if (carLicense.length() == 7) {
                carLicense = replace(carLicense, 3, 6, RegularConstant.STAR);
            } else if (carLicense.length() == 8) {
                carLicense = replace(carLicense, 3, 7, RegularConstant.STAR);
            }

        }
        return carLicense;
    }

    /**
     * 银行卡
     */
    public String bankCard(String bankCardNo, int length) {
        if (0 == length) {
            return bankCardNo;
        } else {
            bankCardNo = bankCardNo.trim();
            if (bankCardNo.length() < 9) {
                return bankCardNo;
            } else {
                int midLength = length - 8;
                StringBuilder buf = new StringBuilder();
                buf.append(bankCardNo, 0, 4);

                for(int i = 0; i < midLength; ++i) {
                    if (i % 4 == 0) {
                        buf.append(' ');
                    }

                    buf.append(RegularConstant.STAR);
                }

                buf.append(' ').append(bankCardNo, length - 4, length);
                return buf.toString();
            }
        }
    }

    /**
     * 将部分位替换成其它字符
     */
    public String replace(CharSequence str, int startInclude, int endExclude, char replacedChar) {
        if (str == null || str.length() == 0) {
            return null == str ? null : str.toString();
        } else {
            String originalStr = str.toString();
            int[] strCodePoints = originalStr.codePoints().toArray();
            int strLength = strCodePoints.length;
            if (startInclude > strLength) {
                return originalStr;
            } else {
                if (endExclude > strLength) {
                    endExclude = strLength;
                }

                if (startInclude > endExclude) {
                    return originalStr;
                } else {
                    StringBuilder stringBuilder = new StringBuilder();

                    for(int i = 0; i < strLength; ++i) {
                        if (i >= startInclude && i < endExclude) {
                            stringBuilder.append(replacedChar);
                        } else {
                            stringBuilder.append(new String(strCodePoints, i, 1));
                        }
                    }

                    return stringBuilder.toString();
                }
            }
        }
    }

    public String repeat(char ch, int repeat) {
        if (repeat <= 0) {
            return "";
        } else {
            char[] buf = new char[repeat];
            Arrays.fill(buf, ch);
            return new String(buf);
        }
    }

    public String rightPad(String str, int size, char padChar) {
        if (str == null) {
            return null;
        } else {
            int pads = size - str.length();
            if (pads <= 0) {
                return str;
            } else {
                return pads > 8192 ? rightPad(str, size, String.valueOf(padChar)) : str.concat(repeat(padChar, pads));
            }
        }
    }

    public boolean isEmpty(CharSequence cs) {
        return cs == null || cs.length() == 0;
    }

    public String rightPad(String str, int size, String padStr) {
        if (str == null) {
            return null;
        } else {
            if (isEmpty(padStr)) {
                padStr = " ";
            }

            int padLen = padStr.length();
            int strLen = str.length();
            int pads = size - strLen;
            if (pads <= 0) {
                return str;
            } else if (padLen == 1 && pads <= 8192) {
                return rightPad(str, size, padStr.charAt(0));
            } else if (pads == padLen) {
                return str.concat(padStr);
            } else if (pads < padLen) {
                return str.concat(padStr.substring(0, pads));
            } else {
                char[] padding = new char[pads];
                char[] padChars = padStr.toCharArray();

                for(int i = 0; i < pads; ++i) {
                    padding[i] = padChars[i % padLen];
                }

                return str.concat(new String(padding));
            }
        }
    }
}
